package com.conn3cted.phrasebook.domain;

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
import java.util.Set;

import com.conn3cted.phrasebook.domain.Phrase;

import java.util.HashSet;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.OneToMany;
import javax.persistence.CascadeType;
import javax.persistence.PersistenceContext;
import javax.persistence.Version;

@Configurable
@Entity
public class Person {

	@NotNull
	@Size(max = 100)
	private String firstName;

	@NotNull
	@Size(max = 100)
	private String lastName;

	@NotNull
	@Size(max = 20)
	private String dob;

	@NotNull
	@Size(max = 100)
	private String origin;

	@NotNull
	@Size(max = 300)
	private String occupation;

	@NotNull
	@Size(max = 2000)
	private String summary;

	@NotNull
	@Size(max = 40)
	private String password;

	@OneToMany(cascade = CascadeType.ALL)
	private Set<Phrase> phrases = new HashSet<Phrase>();

    @Lob
    @Basic(fetch = FetchType.LAZY)
    private byte[] file;

    private String fileContentType;
   
    
    

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("Dob: ").append(getDob()).append(", ");
		sb.append("FirstName: ").append(getFirstName()).append(", ");
		sb.append("Id: ").append(getId()).append(", ");
		sb.append("LastName: ").append(getLastName()).append(", ");
		sb.append("Occupation: ").append(getOccupation()).append(", ");
		sb.append("Origin: ").append(getOrigin()).append(", ");
		sb.append("Password: ").append(getPassword()).append(", ");
        sb.append("Phrases: ").append(getPhrases() == null ? "null" : getPhrases().size()).append(", ");
		sb.append("Summary: ").append(getSummary()).append(", ");
		sb.append("Version: ").append(getVersion());
		return sb.toString();
	}

	public String getFirstName() {
		return this.firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return this.lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getDob() {
		return this.dob;
	}

	public void setDob(String dob) {
		this.dob = dob;
	}

	public String getOrigin() {
		return this.origin;
	}

	public void setOrigin(String origin) {
		this.origin = origin;
	}

	public String getOccupation() {
		return this.occupation;
	}

	public void setOccupation(String occupation) {
		this.occupation = occupation;
	}

	public String getSummary() {
		return this.summary;
	}

	public void setSummary(String summary) {
		this.summary = summary;
	}

	public String getPassword() {
		return this.password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Set<Phrase> getPhrases() {
		return this.phrases;
	}

	public void setPhrases(Set<Phrase> phrases) {
		this.phrases = phrases;
	}

	@PersistenceContext
	transient EntityManager entityManager;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id")
	private Long id;

	@Version
	@Column(name = "version")
	private Integer version;

	public Long getId() {
		return this.id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Integer getVersion() {
		return this.version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	@Transactional
	public void persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
		this.entityManager.persist(this);
	}

	@Transactional
	public void remove() {
        if (this.entityManager == null) this.entityManager = entityManager();
		if (this.entityManager.contains(this)) {
			this.entityManager.remove(this);
		} else {
			Person attached = Person.findPerson(this.id);
			this.entityManager.remove(attached);
		}
	}

	@Transactional
	public void flush() {
        if (this.entityManager == null) this.entityManager = entityManager();
		this.entityManager.flush();
	}

	@Transactional
	public void clear() {
        if (this.entityManager == null) this.entityManager = entityManager();
		this.entityManager.clear();
	}

	@Transactional
	public Person merge() {
        if (this.entityManager == null) this.entityManager = entityManager();
		Person merged = this.entityManager.merge(this);
		this.entityManager.flush();
		return merged;
	}

	public static final EntityManager entityManager() {
		EntityManager em = new Person().entityManager;
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
		return em;
	}

	public static long countPeople() {
        return entityManager().createQuery("SELECT COUNT(o) FROM Person o", Long.class).getSingleResult();
	}

	public static List<Person> findAllPeople() {
        return entityManager().createQuery("SELECT o FROM Person o", Person.class).getResultList();
	}

	public static Person findPerson(Long id) {
        if (id == null) return null;
		return entityManager().find(Person.class, id);
	}

	public static Person findPerson(String username, String password) {
		if (username == null || password == null) {
			return null;
		}
		List<Person> resultList = entityManager()
				.createQuery(
						"SELECT o FROM Person o where firstName = ?1 and password = ?2",
						Person.class).setParameter(1, username)
				.setParameter(2, password).getResultList();

		if (resultList.size() > 0 && resultList != null) {
			return resultList.get(0);
		}
		return null;
	}

	public static List<Person> findPersonEntries(int firstResult, int maxResults) {
        return entityManager().createQuery("SELECT o FROM Person o", Person.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
	}

	public byte[] getFile() {
		return file;
	}

	public void setFile(byte[] file) {
		this.file = file;
	}

	public String getFileContentType() {
		return fileContentType;
	}

	public void setFileContentType(String fileContentType) {
		this.fileContentType = fileContentType;
	}
}
